package week2;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Created by dyc on 2016/11/10.
 */
public class ResizableArray<Item>{

    public static final int ITERATOR_STACK = 0;
    public static final int ITERATOR_QUEUE = 1;

    private Item[] data;
    private int currentIndex;

    public ResizableArray(int capacity){
        this.data = (Item[])new Object[capacity];
        this.currentIndex = -1;
    }

    private void resize(int size){
        Item[] buf = (Item[])new Object[size];
        int end = Integer.min(buf.length,data.length);
        for (int i = 0; i < end; i++){
            buf[i] = data[i];
        }
        data = buf;
    }

    public void set(int index, Item data){
        if (index < 0 || index > currentIndex)
            throw new IndexOutOfBoundsException();
        this.data[index] = data;
    }

    public void add(Item data){
        if (currentIndex + 1 == this.data.length)
            resize(2 * this.data.length);
        this.data[++currentIndex] = data;
    }

    public void insert(int index,Item data){
        if (index < 0 || index > currentIndex)
            throw new IndexOutOfBoundsException();
        if (currentIndex + 1 == this.data.length)
            resize(2 * this.data.length);
        for (int i = currentIndex + 1; i > index; i--){
            this.data[i] = this.data[i - 1];
        }
        this.data[index] = data;
        currentIndex++;
    }

    public Item remove(){
        if (currentIndex == -1)
            throw new NoSuchElementException();
        Item data = this.data[currentIndex];
        this.data[currentIndex--] = null;
        if (currentIndex < this.data.length / 4)
            resize(this.data.length / 2);
        return data;
    }

    public Item removeAt(int index){
        if (index < 0 || index > currentIndex)
            throw new IndexOutOfBoundsException();
        Item data = this.data[index];
        this.data[index] = null;
        for (int i = index + 1; i <= currentIndex; i++)
            this.data[i - 1] = this.data[i];
        currentIndex--;
        if (currentIndex < this.data.length / 4)
            resize(this.data.length / 2);
        return data;
    }

    public int size(){
        return currentIndex + 1;
    }

    public Iterator<Item> iterator(int type) {
        switch (type){
            case ITERATOR_QUEUE:
            case ITERATOR_STACK:
                return new SequentialIterator(type);
            default:
                throw new IllegalArgumentException();
        }
    }

    private class SequentialIterator implements Iterator<Item>{
        private int current;
        private int iteratorType;

        public SequentialIterator(int iteratorType){
            this.iteratorType = iteratorType;
            if (iteratorType == ITERATOR_QUEUE)
                current = 0;
            else if (iteratorType == ITERATOR_STACK)
                current = currentIndex;
            else
                throw new IllegalArgumentException();
        }

        @Override
        public boolean hasNext() {
            if (iteratorType == ITERATOR_QUEUE)
                return current <= currentIndex;
            else
                return current >= 0;
        }

        @Override
        public Item next() {
            Item item = data[current];
            if (iteratorType == ITERATOR_QUEUE)
                current++;
            else
                current--;
            return item;
        }
    }
}
